Sort
Table of Contents
Overview
According to information theory, no comparison sort can perform better than comparisons in the average case.
Timesort | Merge sort | Quicksort | Insertion sort | Selection sort | Smoothsort | |
---|---|---|---|---|---|---|
Best case | Θ(n) | Θ(nlogn) | Θ(nlogn) | Θ(n) | Θ(n2) | Θ(n) |
Average case | Θ(nlogn) | Θ(nlogn) | Θ(nlogn) | Θ(n2) | Θ(n2) | Θ(nlogn) |
Worst case | Θ(nlogn) | Θ(nlogn) | Θ(n2) | Θ(n2) | Θ(n2) | Θ(nlogn) |
Space complexity | Θ(n) | Θ(n) | Θ(logn) | Θ(1) | Θ(1) | Θ(1) |
Note, however, that the space complexity of both Timsort and merge sort can be reduced to at the cost of speed
Comparison of Sorting Algorithms
- Comparison of Internal Sorting Algorithms http://attractivechaos.wordpress.com/2008/08/28/comparison-of-internal-sorting-algorithms/
- Comparison of several sorting algorithms http://warp.povusers.org/SortComparison/
Merge sort
def mergesort(lst, left=0, right=None): if right is None: right = len(lst) - 1 if left >= right: return middle = (left + right) // 2 mergesort(lst, left, middle) mergesort(lst, middle + 1, right) i, end_i, j = left, middle, middle + 1 while i <= end_i and j <= right: if lst[i] <= lst[j]: i += 1 continue lst[i], lst[i+1:j+1] = lst[j], lst[i:j] i, end_i, j = i + 1, end_i + 1, j + 1
Quicksort
def quicksort(lst, left=0, right=None): if right is None: right = len(lst) - 1 l = left r = right if l <= r: mid = (lst[left] + lst[right]) / 2 while l < r: while l <= right and lst[l] < mid: l += 1 while r >= left and lst[r] > mid: r -= 1 if l <= r: lst[l], lst[r] = lst[r], lst[l] l += 1 r -= 1 if left < r: quicksort(lst, left, r) if l < right: quicksort(lst, l, right)
Insertion sort
def insertionsort(lst): for i in range(1, len(lst)): for j in range(i): if lst[i] < lst[j]: x = lst.pop(i); lst.insert(j, x);
Selection sort
def selectionsort(lst): for i in range(len(lst) - 1, -1, -1): m = lst.index(max(lst[:i+1])) lst[m], lst[i] = lst[i], lst[m]
Smoothsort1
# Possibly replace with a generator that produces Leonardo numbers? # That would be of limited utility since this is all of them up to 31 bits. LP = [ 1, 1, 3, 5, 9, 15, 25, 41, 67, 109, 177, 287, 465, 753, 1219, 1973, 3193, 5167, 8361, 13529, 21891, 35421, 57313, 92735, 150049, 242785, 392835, 635621, 1028457, 1664079, 2692537, 4356617, 7049155, 11405773, 18454929, 29860703, 48315633, 78176337, 126491971, 204668309, 331160281, 535828591, 866988873 ] # Solution for determining number of trailing zeroes of a number's binary representation. # Taken from http://www.0xe3.com/text/ntz/ComputingTrailingZerosHOWTO.html # don't much like the magic numbers, but they really are magic. MultiplyDeBruijnBitPosition = [ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9] def trailingzeroes(v): return MultiplyDeBruijnBitPosition[(((v & -v) * 0x077CB531L) >> 27) & 0b11111] def sift(lst, pshift, head): while pshift > 1: rc = head - 1 lc = head - 1 - LP[pshift - 2] if lst[head] >= lst[lc] and lst[head] >= lst[rc]: break elif lst[rc] > lst[lc]: lst[head], lst[rc] = lst[rc], lst[head] head = rc pshift -= 2 else: lst[head], lst[lc] = lst[lc], lst[head] head = lc pshift -= 1 def trinkle(lst, p, pshift, head): while p != 1: priorHeap = head - LP[pshift] if lst[head] >= lst[priorHeap]: break lst[head], lst[priorHeap] = lst[priorHeap], lst[head] head = priorHeap trail = trailingzeroes(p & ~1) p >>= trail pshift += trail sift(lst, pshift, head) def smoothsort(lst): """ case 0: If there are no elements in the heap, add a tree of order 1 case 1: If the last two heaps have sizes that differ by one, merge them case 2: If the last heap has LP 1, add a singleton heap of LP 0 case 3: add a singleton heap of LP 1 """ #case 0: p = 1 pshift = 1 head = 0 while head < len(lst) - 1: #case 1: if (p & 3) == 3: sift(lst, pshift, head) p >>= 2 pshift += 2 else: if LP[pshift - 1] >= len(lst) - 1 - head: trinkle(lst, p, pshift, head) else: sift(lst, pshift, head) #case 2 if pshift == 1: p <<= 1 pshift = 0 else: #case 3 p <<= pshift - 1 pshift = 1 p |= 1 head += 1 trinkle(lst, p, pshift, head) while pshift != 1 or p != 1: if pshift <= 1: trail = trailingzeroes(p & ~1) p >>= trail pshift += trail else: p <<= 2 p ^= 7 pshift -= 2 #left child trinkle(lst, p >> 1, pshift + 1, head - LP[pshift] - 1) trinkle(lst, p, pshift, head - 1) head -= 1
Timesort2
bitonicsort3
import math ASCENDING = True DESCENDING = False def compare(lst, i, j, dir): if(dir == (lst[i] > lst[j])): lst[i], lst[j] = lst[j], lst[i] def merge(lst, l, n, dir): if n > 1: k = n / 2 for i in range(l, l + k): compare(lst, i, i + k, dir) merge(lst, l, k, dir) merge(lst, l + k, k, dir) def _bitonicsort(lst, l, n, dir): if n > 1: k = n / 2 _bitonicsort(lst, l, k, ASCENDING) _bitonicsort(lst, l + k, k, DESCENDING) merge(lst, l, n , dir) def bitonicsort(lst): # Length of list must be 2**x, where x is an integer. assert math.modf(math.log(len(lst), 2))[0] == 0 _bitonicsort(lst, 0, len(lst), ASCENDING)
bubblesort
def bubblesort(lst): bound = len(lst) - 1 while 1: t = 0 for j in range(bound): if lst[j] > lst[j + 1]: lst[j + 1], lst[j] = lst[j], lst[j + 1] t = j if t == 0: break bound = t
cocktailsort
def cocktailsort(lst): begin, end = 0, len(lst) - 1 finished = False while not finished: finished = True for i in xrange(begin, end): if lst[i] > lst[i + 1]: lst[i], lst[i + 1] = lst[i + 1], lst[i] finished = False if finished: break end -= 1 for i in reversed(xrange(begin,end)): if lst[i] > lst[i + 1]: lst[i], lst[i + 1] = lst[i + 1], lst[i] finished = False begin += 1
cmobsort
def combsort(lst): gap = len(lst) swap = False while 1: gap = int(gap / 1.25) swap = False for i in xrange(len(lst) - gap): if lst[i] > lst[i + gap]: lst[i], lst[i + gap] = lst[i + gap], lst[i] swap = True if not swap and gap <= 1: break
cyclesort4
gnomesort
def gnomesort(lst): i = 0 while i < len(lst): if i == 0 or lst[i] > lst[i - 1]: i += 1 else: lst[i], lst[i - 1] = lst[i - 1], lst[i] i -= 1
heapsort
def sift(lst, start, count): root = start while (root * 2) + 1 < count: child = root * 2 + 1 if child < count - 1 and lst[child] < lst[child + 1]: child += 1 if lst[root] < lst[child]: lst[root], lst[child] = lst[child], lst[root] root = child else: return def heapsort(lst): start = len(lst) / 2 - 1 end = len(lst) - 1 while start >= 0: sift(lst, start, len(lst)) start -= 1 while end > 0: lst[end], lst[0] = lst[0], lst[end] sift(lst, 0, end) end -= 1
oddevensort
def oddevensort(lst, nloops=2): finished = False while not finished: finished = True for n in xrange(nloops): for i in xrange(n, len(lst) - 1, nloops): if lst[i] > lst[i + 1]: lst[i], lst[i + 1] = lst[i + 1], lst[i] finished = False
radixsort
from itertools import chain def radixsort(lst): is_sorted = lambda l: all([a < b for a,b in zip(l[:-1], l[1:])]) shift = 1 zeros = [] ones = [] while not is_sorted(lst): orig = lst[:] while len(orig) != 0: item = orig.pop(0) if (item & shift) == 0: zeros.append(item) else: ones.append(item) for i, item in enumerate(chain(zeros, orig, ones)): lst[i] = item if is_sorted(lst): return shift = shift << 1 zeros = [] ones = []
shellsort
def shellsort(lst): gaps = [5 , 3, 1] for gap in gaps: for i in xrange(gap, len(lst)): temp = lst[i] j = i; while j>= gap and lst[j - gap] > temp: lst[j] = lst[j - gap] j -= gap lst[j]= temp
stoogesort
def stoogesort(lst, i=0, j=None): if j is None: j = len(lst) - 1 if lst[j] < lst[i]: lst[j], lst[i] = lst[i], lst[j] if j - i > 1: t = (j - i + 1) // 3 stoogesort(lst, i, j - t) stoogesort(lst, i + t, j) stoogesort(lst, i, j - t)